class HtmlNode{
    children=[]
    constructor(selector) {
        if (!selector){
            throw '非法的选择器'
        }
        //提取标签名称
        let tagName=selector.match(/^[^#\.\[]+/)||['div']
        this.el=document.createElement(tagName[0])

        //提取ID
        let id=selector.match(/#.+?\.?/)
        if (id){
            id=id[0].substr(1)
            if (id.includes('.')){
                id=id.substring(0,id.length-1)
            }
            this.el.id=id
        }
        //提取属性
        let attrs=selector.match(/\[.+?\]/g)
        if (attrs){
            attrs.map(attr=>{
                attr=attr.substring(1,attr.length-1)
                attr=attr.split("=")
                let attribute = document.createAttribute(attr[0]);
                if (attr.length === 2){
                    attribute.value=attr[1]
                }
                return attribute
            }).forEach(attr=>{
                this.el.setAttributeNode(attr)
            });
            selector=selector.replace(/\[.+?\]/g,'')
        }

        //提取class
        let classlist=selector.match(/\.[^.#\[\]]+/g)
        if (classlist){
            this.el.classList.add.apply(this.el.classList,classlist.map(cla=>cla.substr(1)))
        }


        if (arguments.length===2){
            if (arguments[1] instanceof HtmlNode){
                arguments[1].appendChild(this)
            }else if(arguments[1] instanceof HTMLElement){
                arguments[1].appendChild(this.el)
            }else if(typeof arguments[1] === "string"){
                let element = document.querySelector(arguments[1]);
                if (element) {
                    element.appendChild(this.el)
                }
            }
        }
    }

    addEventListener(eventName,listener){
        this.el.addEventListener(eventName,e=>{
            listener.call(this,e)
        })
    }

    /**
     * 将value属性与对象的指定属性绑定(如果有value属性)
     * @param obj 对象
     * @param name 属性名
     */
    bindValue(obj,name){
        if(this.el.value){
            let $this=this;
            Object.defineProperty(obj,name,{
                enumerable:true,
                configurable:true,
                set(value){
                    $this.el.value=value
                },
                get(){
                    return $this.el.value
                }
            })
            this.el.addEventListener('input',e=>{
                this.value=e.target.value
            })
        }

    }

    /**
     * 将对象文本节点与对象的指定属性进行绑定
     * @param obj
     * @param name
     * @returns {string}
     */
    bindTextContent(obj,name,attributes){
        let $this=this;
        let defaultAttributes={
            enumerable:true,
            configurable:true,
            set(value){
                $this.textContent=value
            },
            get(){
                return $this.textContent
            }
        };
        Object.assign(defaultAttributes,attributes)
        Object.defineProperty(obj,name,defaultAttributes)
    }

    /**
     * 获得value属性值(如果有value属性)
      * @returns {*}
     */
    get value(){
        return this.el.value
    }

    /**
     * 设置value属性值(如果有value属性)
     * @param value
     */
    set value(value){
        if (this.el.value) {
            this.el.value = value
        }
    }

    /**
     * 获取文本内容
     * @returns {string|string}
     */
    get textContent(){
        return this.el.textContent
    }

    /**
     * 设置文本内容
     * @param text 文本内容
     */
    set textContent(text){
        this.el.textContent=text
    }

    /**
     * 获得DataSet对象
     * @returns {DOMStringMap}
     */
    get dataset(){
        return this.el.dataset;
    }

    /**
     * 设置属性
     * @param name 属性名称
     * @param value 属性值
     */
    setAttribute(name,value){
        let attr = document.createAttribute(name);
        if (value) {
            attr.value = value
        }
        this.el.setAttributeNode(attr)
    }

    /**
     * 获取属性值
     * @param name 属性名称
     * @returns {string}
     */
    getAttribute(name){
        return this.el.getAttribute(name)
    }

    /**
     * 为当前节点添加子节点
     * @param node
     */
    appendChild(node){
        if (node instanceof HtmlNode){
            this.children.push(node)
            this.el.appendChild(node.el)
            return
        }else if (node instanceof HTMLElement){
            this.el.appendChild(node)
            return
        }else if(typeof node === "string"){
            let element = document.querySelector(node);
            if (element){
                this.el.appendChild(element)
                return
            }
        }
        throw '入参必须是[HtmlNode,HTMLElement,string]类型'
    }
    /**
     * 将当前节点添加到指定节点下
     * @param node
     */
    appendTo(node){
        if (node instanceof HtmlNode){
            node.el.appendChild(this.el)
            return
        }else if (node instanceof HTMLElement){
            node.appendChild(this.el)
            return
        }else if(typeof node === "string"){
            let element = document.querySelector(node);
            if (element){
                element.appendChild(this.el)
                return
            }
        }
        throw '入参必须是[HtmlNode,HTMLElement,string]类型'
    }

    hasClass(className){
        return this.el.classList.contains(className)
    }

    /**
     * 添加或删除样式类
     * @param className
     */
    toggleClass(className){
        if(this.hasClass(className)){
            this.el.classList.remove(className)
        }else{
            this.el.classList.add(className)
        }
    }

    css(name,value){
        let cssObj={}
        if (arguments.length == 1){
            if (typeof name === 'object'){
                cssObj=name
            }else if(typeof name === 'string'){
                return this.el.style[name]
            }
        }else{
            cssObj[name]=value
        }
        Object.keys(cssObj).forEach(name=>this.el.style[name]=cssObj[name])
    }
}